package com.fll.codeworld.doc;

import com.spire.doc.*;
import com.spire.doc.collections.DocumentObjectCollection;
import com.spire.doc.collections.ParagraphCollection;
import com.spire.doc.collections.SectionCollection;
import com.spire.doc.documents.*;
import com.spire.doc.fields.ShapeObject;
import com.spire.doc.fields.TextRange;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.awt.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * spireDoc操作工具类
 *
 * @author fff
 * @date 2022/4/20
 */
@Slf4j
public class SpireUtil {
    /**
     * spire生成目录
     * 注意:使用此方法动态生成目录时,需要在制作ftl模板时删除原有目录
     *
     * @param path         生成word的文件夹路径
     * @param paragraphNum 插入目录的段落下标(此下标需要根据实际业务中,分析ftl模板获得)
     * @param upperLevel   目录最高层级
     * @return Configuration
     */
    public static String getPageCount(String path, Integer paragraphNum, Integer upperLevel) {
        if (StringUtils.isNotBlank(path) && paragraphNum != null && upperLevel != null) {
            log.info("======生成目录==开始====");
            try {
                Document doc = new Document(path);
                //通过域代码添加目录表(1-3级)
                doc.getSections().get(0).getParagraphs().get(paragraphNum).appendTOC(1, upperLevel);
                doc.updateTableOfContents();
                doc.saveToFile(path);
                //去除警告
                removeSpireWarning(path);
            } catch (Exception e) {
                log.info("======生成目录发生异常!!!!====");
                e.printStackTrace();
            }
            log.info("======生成目录==完成====");
        }
        return path;
    }

    /**
     * 插入页码(重新)
     * 注意:总也数可以修改:doc.getPageCount(),在实际的业务中,可以根据需要动态修改总页数实
     *
     * @param path     文档保存路径
     * @param document 可以为空
     */
    public static String HeaderFooterForOddAndEvenPages(String path, Document document) {
        if (StringUtils.isNotBlank(path)) {
            log.info("====重置页码====开始===");
            try {
                if (Objects.isNull(document)) {
                    document = new Document(path);
                }
                //获取第一个节中的页脚
                HeaderFooter footer = document.getSections().get(1).getHeadersFooters().getFooter();
                //添加段落到页脚
                Paragraph footerParagraph = footer.addParagraph();
                //添加页脚域样式
                ParagraphStyle footerStyle = (ParagraphStyle) Style.createBuiltinStyle(BuiltinStyle.Footer, document);
                footerStyle.setName("style");
                footerStyle.getCharacterFormat().setFontName("仿宋_GB2312");
                footerStyle.getCharacterFormat().setFontSize(9);
                document.getStyles().add(footerStyle);
                footerParagraph.applyStyle("style");
                //添加文字、页码域和总页数域到段落
                footerParagraph.appendText("第");
                footerParagraph.appendField("page number", FieldType.Field_Page);
                footerParagraph.appendText("页 共");
                footerParagraph.appendField("number of pages", FieldType.Field_Num_Pages);
                footerParagraph.appendText("页");
                //设置从第一页开始计数(页码重新计数)
                document.getSections().get(1).getPageSetup().setRestartPageNumbering(true);
                document.getSections().get(1).getPageSetup().setPageStartingNumber(1);
                //将段落居中
                footerParagraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
                //判断文档是否含多个节
                if (document.getSections().getCount() > 1) {
                    //遍历除第一节以外的其他节
                    for (int i = 1; i < document.getSections().getCount(); i++) {
                        //在当前节重新开始编页码
                        document.getSections().get(i).getPageSetup().setRestartPageNumbering(true);
                        //从1开始编页码
                        document.getSections().get(i).getPageSetup().setPageStartingNumber(1);
                    }
                }
                //重新保存文件
                document.saveToFile(path);
                //去除警告
                removeSpireWarning(path);
            } catch (Exception e) {
                log.info("设置文档页码时发生异常!!!");
                e.printStackTrace();
            }
            log.info("====重置页码====完成===");
        }
        return path;
    }

    /**
     * @param path     文档保存路径
     * @param document 可以为空
     * @param style    目录前添加的样式 ,例如:在目录添加★
     * @author fll
     * @description 修改目录文本样式 (示例:给目录添加★)
     * @date 2022/04/21
     */
    public static String updateTocText(String path, Document document, String style) {
        if (StringUtils.isNotBlank(path) && StringUtils.isNotBlank(style)) {
            try {
                if (Objects.isNull(document)) {
                    document = new Document(path);
                }
                log.info("====修改目录样式====开始===");
                for (Section sec : (Iterable<? extends Section>) document.getSections()) {
                    //遍历body下面所有对象
                    for (DocumentObject obj : (Iterable<? extends DocumentObject>) sec.getBody().getChildObjects()) {
                        if (obj instanceof Paragraph) {
                            Paragraph para = (Paragraph) obj;
                            //查找含有TOC域的段落
                            for (DocumentObject tr : (Iterable<? extends DocumentObject>) para.getChildObjects()) {
                                if (tr.getDocumentObjectType() == DocumentObjectType.TOC || tr.getDocumentObjectType() == DocumentObjectType.Field) {
                                    changeText(para, style);
                                    break;
                                }
                            }
                        }
                    }
                }
                //重新保存文件
                document.saveToFile(path);
                //去除警告
                removeSpireWarning(path);
            } catch (Exception e) {
                log.info("修改目录样式时发生异常!!!");
                e.printStackTrace();
            }
        }
        log.info("====修改目录样式====完成===");
        return path;
    }

    private static void changeText(Paragraph para, String style) {
        for (DocumentObject tr : (Iterable<? extends DocumentObject>) para.getChildObjects()) {
            if (tr.getDocumentObjectType() == DocumentObjectType.Text_Range) {
                TextRange textRange = (TextRange) tr;
                textRange.setText(style + textRange.getText());
                break;
            }
        }
    }

    /**
     * 修改目录行距(固定行距)
     *
     * @param path     文档保存路径
     * @param document 可以为空
     * @param value    行距值
     */
    public static String updateTocLineSpace(String path, Document document, float value) {
        if (StringUtils.isNotBlank(path) && Objects.nonNull(value)) {
            try {
                if (Objects.isNull(document)) {
                    document = new Document(path);
                }
                //获取所有节
                SectionCollection sections = document.getSections();
                for (Section section : (Iterable<? extends Section>) sections) {
                    //获取所有段落
                    ParagraphCollection paragraphs = section.getParagraphs();
                    for (Paragraph paragraph : (Iterable<? extends Paragraph>) paragraphs) {
                        //获取段落下的内容
                        DocumentObjectCollection childObjects = paragraph.getChildObjects();
                        for (DocumentObject obj : (Iterable<? extends DocumentObject>) childObjects) {
                            //添加判断
                            if (obj.getDocumentObjectType() == DocumentObjectType.TOC || obj.getDocumentObjectType() == DocumentObjectType.Field) {
                                //设置目行距为固定值
                                paragraph.getFormat().setLineSpacingRule(LineSpacingRule.Exactly);
                                paragraph.getFormat().setLineSpacing(value);
                            }
                        }
                    }
                }
                //重新保存文件
                document.saveToFile(path);
                //去除警告
                removeSpireWarning(path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return path;
    }

    /**
     * 修改图形颜色
     * 注意:(修改指定图形的线条颜色或者填充颜色)
     *
     * @param path        文档保存路径
     * @param document    可以为空
     * @param fillColor   填充颜色
     * @param strokeColor 线条颜色
     * @param properties  图形下标(从0开始)
     */
    public static String updateShapeColor(String path, Document document, Color fillColor, Color strokeColor, Integer... properties) {
        List<Integer> list = Arrays.asList(properties);
        int shapeCount = 0;
        if (StringUtils.isNotBlank(path) && properties.length > 0) {
            if (Objects.nonNull(fillColor) || Objects.nonNull(strokeColor)) {
                try {
                    if (Objects.isNull(document)) {
                        document = new Document(path);
                    }
                    for (Section sec : (Iterable<? extends Section>) document.getSections()) {
                        for (int i = 0; i < sec.getBody().getChildObjects().getCount(); i++) {
                            DocumentObject obj = sec.getBody().getChildObjects().get(i);
                            if (obj instanceof Paragraph) {
                                Paragraph para = (Paragraph) obj;
                                for (DocumentObject tr : (Iterable<? extends DocumentObject>) para.getChildObjects()) {
                                    //修改线条样式
                                    if (tr.getDocumentObjectType() == DocumentObjectType.Shape) {
                                        for (int k = 0; k < para.getChildObjects().getCount(); k++) {
                                            if (ShapeObject.class.getTypeName().equals(para.getChildObjects().get(k).getClass().getTypeName())) {
                                                if (list.contains(shapeCount)) {
                                                    ShapeObject rectangle = (ShapeObject) para.getChildObjects().get(k);
                                                    if (Objects.nonNull(fillColor)) {
                                                        rectangle.setFillColor(fillColor);
                                                    }
                                                    if (Objects.nonNull(strokeColor)) {
                                                        rectangle.setStrokeColor(strokeColor);
                                                    }
                                                }
                                                shapeCount = shapeCount + 1;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    //重新保存文件
                    System.out.println("shapeCount:" + shapeCount);
                    document.saveToFile(path);
                    //去除警告
                    removeSpireWarning(path);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return path;
    }

    /**
     * 设置正文样式(行距/字体/字号)
     *
     * @param path         文档保存路径
     * @param document     可以为空
     * @param sectionIndex 从第几节开始(下标从0开始为第一节)
     * @param LineSpaceNum 行距值 (磅)(如:28)
     * @param fontName     字体(如:"方正仿宋_GBK")
     * @param fontSize     字号(16)
     */
    public static String updateMainTextStyle(String path, Document document, Integer sectionIndex, float LineSpaceNum, String fontName, float fontSize) {
        if (StringUtils.isNotBlank(path) && sectionIndex != null) {
            try {
                if (Objects.isNull(document)) {
                    document = new Document(path);
                }
                //获取所有节()
                SectionCollection sections = document.getSections();
                int sectionsCount = sections.getCount();
                if (sections.getCount() >= sectionIndex) {
                    for (int i = sectionIndex; i < sectionsCount; i++) {
                        ParagraphCollection paragraphs = sections.get(i).getParagraphs();
                        for (Paragraph paragraph : (Iterable<? extends Paragraph>) paragraphs) {
                            //获取段落下的内容
                            DocumentObjectCollection childObjects = paragraph.getChildObjects();
                            for (DocumentObject obj : (Iterable<? extends DocumentObject>) childObjects) {
                                //设置行距为固定值(磅)
                                if (Objects.nonNull(LineSpaceNum)) {
                                    //跳过图片
                                    if (obj.getDocumentObjectType() != DocumentObjectType.Picture) {
                                        paragraph.getFormat().clearFormatting();
                                        paragraph.getFormat().setLineSpacingRule(LineSpacingRule.Exactly);
                                        paragraph.getFormat().setLineSpacing(LineSpaceNum);
                                    }
                                }
                                if (obj.getDocumentObjectType() == DocumentObjectType.Text_Range) {
                                    TextRange textRange = (TextRange) obj;
                                    if (textRange.getDocumentObjectType() == DocumentObjectType.Text_Range) {
                                        //设置缩进(此方法设置全文的缩进;需要加判断条件,正常情况下,编辑freemarker模板来调节缩进)
//                                        if (org.apache.commons.lang3.StringUtils.isNotBlank((textRange.getText())) && textRange.getText().length() > 1 && !str.contains(textRange.getText().substring(0, 1))) {
//                                            paragraph.getFormat().setFirstLineIndent(32);
//                                        }
                                        if (StringUtils.isNotBlank(fontName)) {
                                            textRange.getCharacterFormat().setFontName(fontName);
                                        }
                                        if (Objects.nonNull(fontSize)) {
                                            textRange.getCharacterFormat().setFontSize(fontSize);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                //重新保存文件
                document.saveToFile(path);
                //去除警告
                removeSpireWarning(path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return path;
    }


    /**
     * 根据书签复制word
     *
     * @param copyPath   被复制word
     * @param targetPath 目标word
     * @param mark       书签名称
     */
    public static String copyWordByBookMark(String copyPath, String targetPath, String mark) {
        if (StringUtils.isNotBlank(copyPath) && StringUtils.isNotBlank(targetPath) && StringUtils.isNotBlank(mark)) {
            try {
                Document copyDoc = new Document(copyPath);
                Document targetDoc = new Document(targetPath);
                //激活目标文档书签
                BookmarksNavigator bookmarksNavigator = new BookmarksNavigator(targetDoc);
                bookmarksNavigator.moveToBookmark(mark);
                TextBodyPart textBodyPart = bookmarksNavigator.getBookmarkContent();
                //获取目标文档的"节"
                SectionCollection sectionCollection = copyDoc.getSections();
                //遍历所有节,复制所有内容到书签位置(段落和表格)
                for (int i = 0; i < sectionCollection.getCount(); i++) {
                    DocumentObjectCollection objs = sectionCollection.get(i).getBody().getChildObjects();
                    for (int j = 0; j < objs.getCount(); j++) {
                        DocumentObject obj = objs.get(j);
                        if (obj.getDocumentObjectType() == DocumentObjectType.Paragraph || obj.getDocumentObjectType() == DocumentObjectType.Table) {
                            textBodyPart.getBodyItems().add(obj.deepClone());
                        }
                    }
                }
                //替换书签内容
                bookmarksNavigator.replaceBookmarkContent(textBodyPart);
                targetDoc.saveToFile(targetPath);
                targetDoc.dispose();
                //去除警告
                removeSpireWarning(targetPath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return targetPath;
    }


    /**
     * 去出spire.java警告
     *
     * @param path
     */
    private static void removeSpireWarning(String path) {
        if (StringUtils.isNotBlank(path)) {
            try {
                //重新读取生成的文档
                InputStream is = new FileInputStream(path);
                XWPFDocument document = new XWPFDocument(is);
                //以上Spire.Doc 生成的文件会自带警告信息，这里来删除Spire.Doc 的警告
                document.removeBodyElement(0);
                //输出word内容文件流，新输出路径位置
                OutputStream os = new FileOutputStream(path);
                document.write(os);
                log.info("去除警告完成");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 复制全部文档
     *
     * @param copyPath
     * @param targetPath
     * @param sectionIndex 复制到目标文档,从第几节开始(下标从0开始为第一节)
     */
    public static String copyWord(String copyPath, String targetPath, Integer sectionIndex) {
        if (StringUtils.isNotBlank(copyPath) && StringUtils.isNotBlank(targetPath) && Objects.nonNull(sectionIndex)) {
            try {
                //加载文档1
                Document copyDoc = new Document(copyPath);
                //加载文档2
                Document targetDoc = new Document(targetPath);
                if (targetDoc.getSections().getCount() > sectionIndex) {
                    //遍历文档1中的所有子对象
                    for (int i = 0; i < copyDoc.getSections().getCount(); i++) {
                        Section section = copyDoc.getSections().get(i);
                        for (int j = 0; j < section.getBody().getChildObjects().getCount(); j++) {
                            Object object = section.getBody().getChildObjects().get(j);
                            //复制文档1中的正文内容添加到文档2
                            targetDoc.getSections().get(sectionIndex).getBody().getChildObjects().add(((DocumentObject) object).deepClone());
                        }
                    }
                    //保存文档2
                    targetDoc.saveToFile(targetPath, FileFormat.Docx_2013);
                    targetDoc.dispose();
                    //去除警告
                    removeSpireWarning(targetPath);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return targetPath;
    }


    /**
     * word复制段落到目标文档
     *
     * @param copyPath
     * @param targetPath
     * @param copySectionIndex   被复制文档的节(下标从0开始为第一节)
     * @param copyParagraphIndex 被复制文档的段落
     * @param targetSectionIndex 目标文档的节(下标从0开始为第一节)
     */
    public static void copyParagraph(String copyPath, String targetPath, Integer copySectionIndex, Integer copyParagraphIndex, Integer targetSectionIndex) {
        try {
            if (StringUtils.isNotBlank(copyPath) &&
                    StringUtils.isNotBlank(targetPath) &&
                    Objects.nonNull(copySectionIndex) &&
                    Objects.nonNull(copyParagraphIndex) &&
                    Objects.nonNull(targetSectionIndex)) {
                //加载文档1
                Document copyDoc = new Document(copyPath);
                Document targetDoc = new Document(targetPath);
                if (copyDoc.getSections().getCount() > copySectionIndex && targetDoc.getSections().getCount() > targetSectionIndex) {
                    //获取文档1中的第copySectionIndex节
                    Section copySection = copyDoc.getSections().get(copySectionIndex);
                    //获取文档1中的第copyParagraphIndex段
                    Paragraph paragraph = copySection.getParagraphs().get(copyParagraphIndex);
                    //获取文档2中的第targetSectionIndex节
                    Section section2 = targetDoc.getSections().get(targetSectionIndex);
                    //复制文档1中段落，添加到文档2
                    Paragraph newParagraph = (Paragraph) paragraph.deepClone();
                    section2.getParagraphs().add(newParagraph);
                    //保存文档2
                    targetDoc.saveToFile(targetPath, FileFormat.Docx_2013);
                    targetDoc.dispose();
                    //去除警告
                    removeSpireWarning(targetPath);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}